﻿using System;
using System.ComponentModel;
using System.Globalization;
using System.Web;
using System.Web.Mvc;

namespace MvcBootstrapTimepicker
{
    public class BootstrapTimePicker<TModel> : IHtmlString
    {
        private readonly HtmlHelper mHelper;
        private readonly string mFieldName;
        private string mId;
        private bool mShowMeridian;
        private bool mCurrentTime;
        private DateTime? mTime;
        private string mStrTime;
        private int mMinuteStep = 15;
        private bool mSeconds;
        private int mSecondStep = 15;
        private TimePickerSize mSize = TimePickerSize.Large;
        private bool mDisableFocus = true;
        private bool mWidgetInputs;
        private bool mIcon = true;
        private string mInputClass;
        private string mContainerClass;

        internal BootstrapTimePicker(HtmlHelper helper, string fieldName = null, ModelMetadata metadata = null)
        {
            mHelper = helper;
            mFieldName = fieldName;
            if(metadata != null && metadata.Model != null)
            {
                if(metadata.ModelType == typeof(DateTime) || metadata.ModelType == typeof(DateTime?) ||
                    metadata.ModelType == typeof(TimeSpan) || metadata.ModelType == typeof(TimeSpan?))
                {
                    mTime = DateTime.Parse(metadata.Model.ToString());
                }
                else
                {
                    mStrTime = metadata.Model.ToString();
                }
            }
        }

        /// <summary>
        /// Sets the id of the time picker input element.
        /// </summary>
        /// <param name="id">Id</param>
        /// <returns></returns>
        public BootstrapTimePicker<TModel> Id(string id)
        {
            mId = id;
            return this;
        }

        /// <summary>
        /// Sets whether the time picker user 12 or 24 hour format.
        /// </summary>
        /// <param name="theAMPM">If true, 12 hour format is used, otherwise 24 hour.</param>
        /// <returns></returns>
        public BootstrapTimePicker<TModel> AMPM(bool theAMPM)
        {
            mShowMeridian = theAMPM;
            return this;
        }

        /// <summary>
        /// Sets whether the time picker initially displays the current time.
        /// </summary>
        /// <param name="current">If true, current time is displayed</param>
        /// <returns></returns>
        public BootstrapTimePicker<TModel> Current(bool current)
        {
            mCurrentTime = current;
            return this;
        }

        /// <summary>
        /// Sets the time to initially display in the time picker.
        /// </summary>
        /// <param name="time">The time</param>
        /// <returns></returns>
        public BootstrapTimePicker<TModel> Time(TimeSpan time)
        {
            mTime = new DateTime(time.Ticks);
            return this;
        }

        /// <summary>
        /// Sets the time to initially display in the time picker.
        /// </summary>
        /// <param name="time">The time</param>
        /// <returns></returns>
        public BootstrapTimePicker<TModel> Time(string time)
        {
            mStrTime = time;
            return this;
        }

        /// <summary>
        /// Sets the amount of minutes to step in the time picker.
        /// </summary>
        /// <param name="step">Step count</param>
        /// <returns></returns>
        public BootstrapTimePicker<TModel> MinuteStep(int step)
        {
            if(step < 1 || step > 59)
            {
                throw(new ArgumentOutOfRangeException("step",  "Must be between 1 and 59"));
            }
            mMinuteStep = step;
            return this;
        }

        /// <summary>
        /// Whether the time picker should display seconds.
        /// </summary>
        /// <param name="show">If true, seconds are displayed</param>
        /// <returns></returns>
        public BootstrapTimePicker<TModel> ShowSeconds(bool show)
        {
            mSeconds = show;
            return this;
        }

        /// <summary>
        /// Sets the amount of seconds to step in the time picker.
        /// </summary>
        /// <param name="step">Step count</param>
        /// <returns></returns>
        public BootstrapTimePicker<TModel> SecondStep(int step)
        {
            if(step < 1 || step > 59)
            {
                throw(new ArgumentOutOfRangeException("step", "Must be between 1 and 59"));
            }
            mSecondStep = step;
            return this;
        }

        /// <summary>
        /// Sets the width of the time picker.
        /// </summary>
        /// <param name="size">Size</param>
        /// <returns></returns>
        public BootstrapTimePicker<TModel> Size(TimePickerSize size)
        {
            mSize = size;
            return this;
        }

        /// <summary>
        /// Whether it is possible to manually input values. 
        /// </summary>
        /// <param name="manual">If true, manual input is possible.</param>
        /// <returns></returns>
        public BootstrapTimePicker<TModel> ManualEditInput(bool manual)
        {
            mDisableFocus = !manual;
            return this;
        }

        /// <summary>
        /// Whether it is possible to manually input values in the widget. 
        /// </summary>
        /// <param name="manual">If true, manual input is possible.</param>
        /// <returns></returns>
        public BootstrapTimePicker<TModel> ManualEditWidget(bool manual)
        {
            mWidgetInputs = manual;
            return this;
        }

        /// <summary>
        /// Whether the display of the widget is triggered by clicking an icon
        /// or the input itselft. 
        /// </summary>
        /// <param name="icon">If true, clicking the icon triggers the widget display.</param>
        /// <returns></returns>
        public BootstrapTimePicker<TModel> IconWidgetTrigger(bool icon)
        {
            mIcon = icon;
            return this;
        }

        /// <summary>
        /// Sets additional css-class(es) to the time pickers input element.
        /// </summary>
        /// <param name="class">Css-class(es)</param>
        /// <returns></returns>
        public BootstrapTimePicker<TModel> Class(string @class)
        {
            mInputClass = string.Join(" ", new [] {mInputClass, @class});
            return this;
        }

        /// <summary>
        /// Sets additional css-class(es) to the time pickers container div.
        /// </summary>
        /// <param name="class">Css-class(es)</param>
        /// <returns></returns>
        public BootstrapTimePicker<TModel> ContainerClass(string @class)
        {
            mContainerClass = string.Join(" ", new[] { mContainerClass, @class });
            return this;
        }

        [EditorBrowsable(EditorBrowsableState.Never)]
        public virtual string ToHtmlString()
        {
            TagBuilder timePicker = new TagBuilder("div");
            TagBuilder input = new TagBuilder("input");
            string size = mSize != TimePickerSize.Large
                ? mSize == TimePickerSize.Small ? "col-md-2" : "col-md-4"
                : null;
            string defaultTime;

            if(mStrTime != null)
            {
                defaultTime = mStrTime;
            }
            else if(mTime.HasValue)
            {
                CultureInfo culture = mShowMeridian ? CultureInfo.CreateSpecificCulture("en-us") : CultureInfo.CreateSpecificCulture("sv-se");

                defaultTime = mTime.Value.ToString("T", culture);
            }
            else
            {
                defaultTime = mCurrentTime ? "current" : "false";
            }

            timePicker.AddCssClass("bootstrap-timepicker");
            timePicker.AddCssClass(size);
            timePicker.AddCssClass(mContainerClass);
            input.Attributes.Add("id", mId);
            input.Attributes.Add("type", "text");
            input.AddCssClass("form-control");
            input.AddCssClass("mvc-bootstrap-timepicker");
            input.AddCssClass(mInputClass);
            input.Attributes.Add("name", mFieldName);
            input.Attributes.Add("data-show-meridian", mShowMeridian.ToString().ToLower());
            input.Attributes.Add("data-default-time", defaultTime);
            input.Attributes.Add("data-minute-step", mMinuteStep.ToString());
            input.Attributes.Add("data-show-seconds", mSeconds.ToString().ToLower());
            input.Attributes.Add("data-second-step", mSecondStep.ToString());
            input.Attributes.Add("data-disable-focus", mDisableFocus.ToString().ToLower());
            input.Attributes.Add("data-show-inputs", mWidgetInputs.ToString().ToLower());

            timePicker.InnerHtml = input.ToString(TagRenderMode.SelfClosing);
            if(mIcon)
            {
                TagBuilder icon = new TagBuilder("span");

                timePicker.AddCssClass("input-group");
                icon.AddCssClass("input-group-addon");
                icon.AddCssClass("glyphicon");
                icon.AddCssClass("glyphicon-time");
                timePicker.InnerHtml += icon.ToString(TagRenderMode.SelfClosing);
            }


            return(timePicker.ToString());
        }

        [EditorBrowsable(EditorBrowsableState.Never)]
        public override string ToString() { return ToHtmlString(); }
    }
}